package com.fpcms.common.dao; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.jdbc.JdbcUpdateAffectedIncorrectNumberOfRowsException; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; import org.springframework.jdbc.core.support.JdbcDaoSupport; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; import org.springframework.jdbc.support.incrementer.AbstractSequenceMaxValueIncrementer; import org.springframework.jdbc.support.incrementer.DB2SequenceMaxValueIncrementer; import org.springframework.jdbc.support.incrementer.OracleSequenceMaxValueIncrementer; import com.github.rapid.common.beanutils.BeanUtils; import com.github.rapid.common.beanutils.PropertyUtils; import com.github.rapid.common.jdbc.dialect.Dialect; import com.github.rapid.common.jdbc.support.OffsetLimitResultSetExtractor; import com.github.rapid.common.util.SqlRemoveUtil; import com.github.rapid.common.util.page.Page; import com.github.rapid.common.util.page.PageQuery; import com.github.rapid.common.util.page.Paginator; /** * Spring的JDBC基类 * @author badqiu * */ public abstract class BaseSpringJdbcDao extends JdbcDaoSupport { protected final Logger log = LoggerFactory.getLogger(getClass()); protected SimpleJdbcTemplate simpleJdbcTemplate; protected NamedParameterJdbcTemplate namedParameterJdbcTemplate; protected Class getEntityClass(){ throw new UnsupportedOperationException("not yet implements"); } //用于分页的dialect,在线参考: http://code.google.com/p/rapid-framework/wiki/rapid_dialect private Dialect dialect; public void setDialect(Dialect d) { this.dialect = d; } protected void checkDaoConfig() { super.checkDaoConfig(); if(dialect == null) throw new IllegalStateException("'dialect' property must be not null"); log.info("use jdbc dialect:"+dialect); simpleJdbcTemplate = new SimpleJdbcTemplate(getJdbcTemplate()); namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(getJdbcTemplate()); } public SimpleJdbcTemplate getSimpleJdbcTemplate() { return simpleJdbcTemplate; } public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() { return namedParameterJdbcTemplate; } protected void checkSingleRowAffected(String sql,int rowsAffected) throws JdbcUpdateAffectedIncorrectNumberOfRowsException { checkRowAffected(sql,rowsAffected,1); } /** * 检查update调用的rowsAffected必须为正确的行数 * @param sql * @param rowsAffected * @param requiredRowsAffected * @throws JdbcUpdateAffectedIncorrectNumberOfRowsException */ public void checkRowAffected(String sql,int rowsAffected,int requiredRowsAffected) throws JdbcUpdateAffectedIncorrectNumberOfRowsException { if (requiredRowsAffected > 0 && rowsAffected != requiredRowsAffected) { throw new JdbcUpdateAffectedIncorrectNumberOfRowsException(sql, requiredRowsAffected, rowsAffected); } } @SuppressWarnings("all") public Page pageQuery(String sql, PageQuery pageQuery,RowMapper rowMapper) { Map paramMap = new HashMap(PropertyUtils.describe(pageQuery)); return pageQuery(sql,paramMap,queryTotalItems(sql, paramMap),pageQuery.getPageSize(),pageQuery.getPage(),rowMapper); } @SuppressWarnings("all") public Page pageQuery(String sql, Map paramMap,int pageSize, int pageNumber, RowMapper rowMapper) { return pageQuery(sql,paramMap,queryTotalItems(sql, paramMap),pageSize,pageNumber,rowMapper); } @SuppressWarnings("all") private Page pageQuery(String sql, Map paramMap, final int totalItems,int pageSize, int pageNumber, RowMapper rowMapper) { if(totalItems <= 0) { return new Page(new Paginator(pageNumber,pageSize,0)); } Paginator paginator = new Paginator(pageNumber, pageSize, totalItems); List list = pageQueryForList(sql, paramMap,paginator.getOffset(),pageSize,rowMapper); return new Page(list,paginator); } private int queryTotalItems(String querySql,Map paramMap) { //FIXME 未处理group by的 select count(*) from (subquery) //FIXME 性能需要提升,没有group by的情况下,不要采用子查询 // String removedOrderByQuery = "select count(*) from ( " + SqlRemoveUtils.removeOrders(querySql) + " ) as c "; String removedOrderByQuery = "select count(*) " + SqlRemoveUtil.removeSelect(SqlRemoveUtil.removeOrders(querySql)); return getNamedParameterJdbcTemplate().queryForInt(removedOrderByQuery,new MapSqlParameterSource((Map)paramMap)); } static final String LIMIT_PLACEHOLDER = ":__limit"; static final String OFFSET_PLACEHOLDER = ":__offset"; protected List pageQueryForList(String sql, final Map paramMap, int startRow,int pageSize, final RowMapper rowMapper) { //支持limit查询 if(dialect.supportsLimit()) { paramMap.put(LIMIT_PLACEHOLDER.substring(1), pageSize); //支持limit及offset.则完全使用数据库分页 if(dialect.supportsLimitOffset()) { paramMap.put(OFFSET_PLACEHOLDER.substring(1), startRow); sql = dialect.getLimitString(sql,startRow,OFFSET_PLACEHOLDER,pageSize,LIMIT_PLACEHOLDER); startRow = 0; }else { //不支持offset,则在后面查询中使用游标配合limit分页 sql = dialect.getLimitString(sql, 0,null, pageSize,LIMIT_PLACEHOLDER); } pageSize = Integer.MAX_VALUE; } return (List)getNamedParameterJdbcTemplate().query(sql, paramMap, new OffsetLimitResultSetExtractor(startRow,pageSize,rowMapper)); } ///// insert with start /** * 适用sqlserver:identity,mysql:auto_increment 自动生成主键 */ public int insertWithGeneratedKey(Object entity, String insertSql) { KeyHolder keyHolder = new GeneratedKeyHolder(); int affectedRows = getNamedParameterJdbcTemplate().update(insertSql, new BeanPropertySqlParameterSource(entity) , keyHolder); setIdentifierProperty(entity, keyHolder.getKey().longValue()); return affectedRows; } public int insertWithIdentity(Object entity,String insertSql) { return insertWithGeneratedKey(entity, insertSql); } public int insertWithAutoIncrement(Object entity,String insertSql) { return insertWithIdentity(entity,insertSql); } public int insertWithSequence(Object entity,AbstractSequenceMaxValueIncrementer sequenceIncrementer,String insertSql) { Long id = sequenceIncrementer.nextLongValue(); setIdentifierProperty(entity, id); return getNamedParameterJdbcTemplate().update(insertSql, new BeanPropertySqlParameterSource(entity)); } public int insertWithDB2Sequence(Object entity,String sequenceName,String insertSql) { return insertWithSequence(entity, new DB2SequenceMaxValueIncrementer(getDataSource(),sequenceName), insertSql); } public int insertWithOracleSequence(Object entity,String sequenceName,String insertSql) { return insertWithSequence(entity, new OracleSequenceMaxValueIncrementer(getDataSource(),sequenceName), insertSql); } public int insertWithUUID(Object entity,String insertSql) { String uuid = UUID.randomUUID().toString().replace("-", ""); setIdentifierProperty(entity, uuid); return getNamedParameterJdbcTemplate().update(insertSql, new BeanPropertySqlParameterSource(entity)); } /** * 手工分配ID插入 * @param entity * @param insertSql */ public int insertWithAssigned(Object entity,String insertSql) { return getNamedParameterJdbcTemplate().update(insertSql, new BeanPropertySqlParameterSource(entity)); } ///// insert with end /** * 得到主键对应的property */ protected String getIdentifierPropertyName() { throw new UnsupportedOperationException("not yet implements"); } /** * 设置实体的主键值 */ public void setIdentifierProperty(Object entity, Object id) { try { BeanUtils.setProperty(entity, getIdentifierPropertyName(), id); } catch (Exception e) { throw new IllegalStateException("cannot set property value:"+id+" on entityClass:"+entity.getClass()+" by propertyName:"+getIdentifierPropertyName(),e); } } /** * 得到实体的主键值 */ public Object getIdentifierPropertyValue(Object entity) { try { return PropertyUtils.getProperty(entity, getIdentifierPropertyName()); } catch (Exception e) { throw new IllegalStateException("cannot get property value on entityClass:"+entity.getClass()+" by propertyName:"+getIdentifierPropertyName(),e); } } }